package com.labManage.aop;

import com.labManage.dao.LogDao;
import com.labManage.entity.Log;
import com.labManage.entity.User;
import com.labManage.service.LogService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
@Aspect
public class LogAspect {
    @Autowired
    LogDao logDao;
    /***************************************************************************************************************************
     *  @fn             AOP_loginAround
     *  @brief          用于测试环绕通知的切面
     *  @type           非静态方法
     *  @detail         1、@Around注解放在切面方法的上面，表示该切面在目标方法之前之后都可执行，参数只有一个value（value关键词可省略），value
     *                     值为切入点表达式，可理解为目标方法的信息，包括权限类型、返回值类型、包名.类名.方法名(参数名)、异常。其中有些可省略，具体
     *                    可查看文件src/studyFile/AOP.txt
     *                  2、ProceedingJoinPoint pjp：通过pjp.proceed()调用目标方法，是否调用目标方法取决于你，因为目标方法是我们来调用，所以切面
     *                     的功能可写在任意位置，在目标方法之前就是前置通知，在目标之方法之后就是后置通知。
     *                  3、环绕通知的切面方法必须有返回值，推荐使用Object
     *                  4、可以将环绕通知类比jdk的动态代理，ProceedingJoinPoint就相当于Method类，环绕通知是可以改变目标方法结果的，也就是说测试
     *                     类调用目标方法时的返回值为切面中改变目标方法结果的返回值
     *  @param[in]      ProceedingJoinPoint pjp    用来执行目标方法的参数
     *  @return         Object                     返回目标方法的结果
     *  @author         DZH
     *  @date           2021.05.20
     ****************************************************************************************************************************/
    @Around("execution(* com.labManage.service.*.*(..))")
    public Object LogAroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        //获取操作类型
        String handleThing = pjp.getSignature().getName();
        String handleType = "";
        if(handleThing.toLowerCase().indexOf("add")!=-1){
            handleType = "增加";
        }else if(handleThing.toLowerCase().indexOf("delete")!=-1){
            handleType = "删除";
        }else if(handleThing.toLowerCase().indexOf("modify")!=-1){
            handleType = "修改";
        }else if(handleThing.toLowerCase().trim().equals("register")){
            handleType = "注册";
        }else if(handleThing.toLowerCase().trim().equals("login")){
            handleType = "登录";
        }else if(handleThing.toLowerCase().trim().equals("logout")){
            handleType = "注销";
        }else{
            handleType = "查询";
        }
        Object res;
        if(handleType.equals("查询")){
            res = pjp.proceed();
        }else{
            String handlePerson = "";
            Subject subject = SecurityUtils.getSubject();
            User loginUser = null;
            if(subject!=null){
                loginUser = (User) subject.getPrincipal();
                if(loginUser!=null){
                    handlePerson = loginUser.getUsername();
                }else{
                    handlePerson = "";
                }
            }else{
                handlePerson = "";
            }
            //获取方法的输入参数
            Object[] args = pjp.getArgs();
            StringBuilder handleArgs = new StringBuilder();
            for(int i=0;i<args.length;i++){
                handleArgs.append("arg"+(i+1)+":");
                handleArgs.append(args[i]);
            }
            //执行目标方法
            res = pjp.proceed();
            String HandleResult = res.toString();
            Log log = new Log();
            log.setHandleType(handleType);
            log.setHandlePerson(handlePerson);
            log.setHandleTime(new Date());
            log.setHandleArgs(handleArgs.toString());
            log.setHandleThing(handleThing);
            log.setHandleResult(HandleResult);
            if(loginUser!=null){
                log.setHandlePersonNo(loginUser.getUserNo());
            }else {
                log.setHandlePersonNo(null);
            }
            int result = logDao.insertLogInfo(log);
        }
        return res;
    }
}
